import time
import re
from functools import partial, reduce
from typing import ChainMap, Dict, Union

from lark import Token, Tree
from lark.visitors import Transformer_InPlaceRecursive

from exceptions import LiquidFilterCallableError
from constants import EMPTY_REPLACEMENT
from filters import FilterManager, has_filter_params, get_filter_params
from tags import TagManager

"""
NOTE: 目前已经将空格和换行都读入了，不需要记录位置
TODO: 缺少空格的记录
"""


class Transformer(Transformer_InPlaceRecursive):
    def __init__(self, visit_tokens=True, context: Union[ChainMap, Dict] = None):
        self.context = context
        super().__init__(visit_tokens=visit_tokens)

    def start(self, value):
        return "".join(value)

    def root(self, value):
        return "".join(value)

    def output_block(self, value):
        return value[0]

    def html(self, value):
        return value

    def html_block(self, value):
        return value

    def param_value(self, value):
        def _unpack_list(v):
            if isinstance(v, list):
                return _unpack_list(v[0])
            return v

        return _unpack_list(value)

    def html_tag_param(self, value):
        return "".join(value)

    def html_tag_name(self, value):
        return f"<{value[0]}"

    def end_html_tag_name(self, value):
        return f"</{value[0]}>"

    def html_comment(self, value):
        return EMPTY_REPLACEMENT

    def param_name(self, value):
        return value[0]

    def tag_block(self, value):
        return value

    def plain_text(self, value):
        return "".join(value)

    def obj(self, value):
        return value[0]

    def output(self, value):
        def apply_filter(value, filter_func):
            return filter_func(value)
        return reduce(apply_filter, value)

    def PLAIN_TEXT(self, value):
        return value.value

    def NEWLINE(self, value):
        return "\n"

    def EQUAL(self, value):
        return "="

    def string(self, value):
        return value[0]

    def STRING(self, value):
        return value.value.strip("\"'")

    def SINLE_QUOTATION_MARK(self, value):
        return "'"

    def DOUBLE_QUOTATION_MARK(self, value):
        return '"'

    def VARNAME(self, value):
        return value.value

    def LEFT_BRACKET(self, value):
        return "("

    def RIGHT_BRACKET(self, value):
        return ")"

    def filter(self, value):
        filter_func = value[0]
        params = get_filter_params(value)
        if params:
            return partial(filter_func, *params)
        return filter_func

    def filter_name(self, value):
        filter_name = value[0]
        return FilterManager.get_filter(filter_name)
